﻿using Minio.DataModel.Args;
using Minio.DataModel.Encryption;
using Minio.DataModel.Notification;
using Minio.DataModel.Result;
using Minio.DataModel;
using Minio.Exceptions;
using Minio;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleMinio;

public static class MinioHelper
{
    #region 获取 minio 实例

    public static IMinioClient UGetInstance()
    {
        var endpoint = "192.168.1.222:81";
        var accessKey = "admin";
        var secretKey = "12345678";

        IMinioClient minio = new MinioClient().WithEndpoint(endpoint).WithCredentials(accessKey, secretKey).Build();
        return minio;
    }

    #endregion

    #region 操作存储桶

    /// <summary>
    /// 创建存储桶 [只能为小写字母和减号，不能包含 下划线、大写字母和数字]
    /// </summary>
    /// <param name="minio">连接实例</param>
    /// <param name="bucketName">存储桶名称</param>
    /// <returns></returns>
    public static async Task<bool> UMakeBucket(this IMinioClient minio, string bucketName)
    {
        bool flag = false;
        try
        {
            BucketExistsArgs bucketExistsArgs = new BucketExistsArgs();
            bucketExistsArgs.WithBucket(bucketName);
            bool found = await minio.BucketExistsAsync(new BucketExistsArgs().WithBucket(bucketName));
            if (found)
            {
                throw new Exception($"存储桶[{bucketName}]已存在");
            }
            await minio.MakeBucketAsync(new MakeBucketArgs().WithBucket(bucketName));
            flag = true;
        }
        catch (Exception e)
        {
            throw new Exception($"创建存储桶时发生异常：{e.Message}");
        }
        return flag;
    }

    /// <summary>
    /// 列出所有的存储桶
    /// </summary>
    /// <param name="minio">连接实例</param>
    /// <returns></returns>
    public static async Task<Tuple<bool, ListAllMyBucketsResult>> UListBuckets(this IMinioClient minio)
    {
        bool flag = false;
        ListAllMyBucketsResult list;
        try
        {
            list = await minio.ListBucketsAsync();
            flag = true;
        }
        catch (Exception e)
        {
            throw new Exception(e.Message);
        }
        return Tuple.Create(flag, list);
    }

    /// <summary>
    /// 检查存储桶是否存在
    /// </summary>
    /// <param name="minio">连接实例</param>
    /// <param name="bucketName">存储桶名称</param>
    /// <returns></returns>
    public static async Task<bool> UBucketExists(this IMinioClient minio, string bucketName)
    {
        bool flag = false;
        try
        {
            flag = await minio.BucketExistsAsync(new BucketExistsArgs().WithBucket(bucketName));
        }
        catch (Exception e)
        {
            throw new Exception(e.Message);
        }
        return flag;
    }

    /// <summary>
    /// 删除一个存储桶
    /// </summary>
    /// <param name="minio">连接实例</param>
    /// <param name="bucketName">存储桶名称</param>
    /// <returns></returns>
    public static async Task<bool> URemoveBucket(this IMinioClient minio, string bucketName)
    {
        bool flag = false;
        try
        {
            bool found = await minio.BucketExistsAsync(new BucketExistsArgs().WithBucket(bucketName));
            if (found)
            {
                await minio.RemoveBucketAsync(new RemoveBucketArgs().WithBucket(bucketName));
                flag = true;
            }
            else
            {
                throw new Exception($"存储桶[{bucketName}]不存在");
            }
        }
        catch (Exception e)
        {
            throw new Exception(e.Message);
        }
        return flag;
    }

    /// <summary>
    /// 列出存储桶里的对象
    /// </summary>
    /// <param name="minio">连接实例</param>
    /// <param name="bucketName">存储桶名称</param>
    /// <param name="prefix">对象的前缀</param>
    /// <param name="recursive">true代表递归查找，false代表类似文件夹查找，以'/'分隔，不查子文件夹</param>
    public static async Task<Tuple<bool, IObservable<Item>>> UListObjects(this IMinioClient minio, string bucketName, string? prefix = null, bool recursive = true)
    {
        bool flag = false;
        IObservable<Item> observable = null;
        try
        {
            var found = await minio.BucketExistsAsync(new BucketExistsArgs().WithBucket(bucketName));
            if (found)
            {
                observable = minio.ListObjectsAsync(new ListObjectsArgs().WithBucket(bucketName).WithPrefix(prefix).WithRecursive(recursive));
                flag = true;
            }
            else
            {
                throw new Exception($"存储桶[{bucketName}]不存在");
            }
        }
        catch (Exception e)
        {
            throw new Exception(e.Message);
        }
        return Tuple.Create(flag, observable);
    }

    /// <summary>
    /// 列出存储桶中未完整上传的对象
    /// </summary>
    /// <param name="minio">连接实例</param>
    /// <param name="bucketName">存储桶名称</param>
    /// <param name="prefix">对象的前缀</param>
    /// <param name="recursive">true代表递归查找，false代表类似文件夹查找，以'/'分隔，不查子文件夹</param>
    /// <returns></returns>
    public static Tuple<bool, IObservable<Upload>> UListIncompleteUploads(this IMinioClient minio, string bucketName, string? prefix = null, bool recursive = true)
    {
        bool flag = false;
        IObservable<Upload> observable = null;
        try
        {
            var found = minio.BucketExistsAsync(new BucketExistsArgs().WithBucket(bucketName));
            if (found.Result)
            {
                observable = minio.ListIncompleteUploads(new ListIncompleteUploadsArgs().WithBucket(bucketName).WithPrefix(prefix).WithRecursive(recursive));
                flag = true;
            }
            else
            {
                throw new Exception($"存储桶[{bucketName}]不存在");
            }
        }
        catch (Exception e)
        {
            throw new Exception(e.Message);
        }
        return Tuple.Create(flag, observable);
    }

    #endregion

    #region 存储桶策略

    /// <summary>
    /// 获取存储桶或者对象前缀的访问权限
    /// </summary>
    /// <param name="minio">连接实例</param>
    /// <param name="bucketName">存储桶名称</param>
    /// <returns></returns>
    public static async Task<Tuple<bool, string>> UGetPolicy(this IMinioClient minio, string bucketName)
    {
        bool flag = false;
        string policyJson = string.Empty;
        try
        {
            var found = minio.BucketExistsAsync(new BucketExistsArgs().WithBucket(bucketName));
            if (found.Result)
            {
                policyJson = await minio.GetPolicyAsync(new GetPolicyArgs().WithBucket(bucketName));
                flag = true;
            }
            else
            {
                throw new Exception($"存储桶[{bucketName}]不存在");
            }
        }
        catch (Exception e)
        {
            throw new Exception(e.Message);
        }
        return Tuple.Create(flag, policyJson);
    }

    /// <summary>
    /// 针对存储桶和对象前缀设置访问策略
    /// </summary>
    /// <param name="minio">连接实例</param>
    /// <param name="bucketName">存储桶名称</param>
    /// <returns></returns>
    public static async Task<bool> USetPolicy(this IMinioClient minio, string bucketName)
    {
        bool flag = false;
        try
        {
            bool found = await minio.BucketExistsAsync(new BucketExistsArgs().WithBucket(bucketName));
            if (found)
            {
                string policyJson = $$"""
                  {
                            "Version": "2012-10-17",
                    "Statement": [
        {
                        "Effect": "Allow",
                        "Principal": {
                            "AWS": [
                            "*"
                            ]
                        },
                        "Action": [
                        "s3:GetBucketLocation"
                        ],
                        "Resource": [
                        "arn:aws:s3:::{{bucketName}}"
                        ]
                    },
                    {
                        "Effect": "Allow",
                        "Principal": {
                            "AWS": [
                            "*"
                            ]
                        },
                        "Action": [
                        "s3:GetObject"
                        ],
                        "Resource": [
                        "arn:aws:s3:::{{bucketName}}/*"
                        ]
                    }
                ]
    }  
""";
                await minio.SetPolicyAsync(new SetPolicyArgs().WithBucket(bucketName).WithPolicy(policyJson));
                flag = true;
            }
            else
            {
                throw new Exception($"存储桶[{bucketName}]不存在");
            }
        }
        catch (Exception e)
        {
            throw new Exception(e.Message);
        }
        return flag;
    }

    #endregion

    #region 存储桶通知

    /// <summary>
    /// 获取存储桶的通知配置
    /// </summary>
    /// <param name="minio">连接实例</param>
    /// <param name="bucketName">存储桶名称</param>
    /// <returns></returns>
    private static async Task<Tuple<bool, string>> UGetBucketNotification(this IMinioClient minio, string bucketName)
    {
        bool flag = false;
        string Ret = string.Empty;
        try
        {
            bool found = await minio.BucketExistsAsync(new BucketExistsArgs().WithBucket(bucketName));
            if (found)
            {
                BucketNotification notifications = await minio.GetBucketNotificationsAsync(new GetBucketNotificationsArgs().WithBucket(bucketName));
                Ret = notifications.ToXML();
                flag = true;
            }
            else
            {
                throw new Exception($"存储桶[{bucketName}]不存在");
            }
        }
        catch (MinioException e)
        {
            throw new Exception(e.Message);
        }
        return Tuple.Create(flag, Ret);
    }

    /// <summary>
    /// 给存储桶设置通知
    /// </summary>
    /// <param name="minio">连接实例</param>
    /// <param name="bucketName">存储桶名称</param>
    /// <returns></returns>
    private static async Task<bool> USetBucketNotification(this IMinioClient minio, string bucketName)
    {
        bool flag = false;
        try
        {
            bool found = await minio.BucketExistsAsync(new BucketExistsArgs().WithBucket(bucketName));
            if (found)
            {
                BucketNotification notification = new BucketNotification();
                Arn topicArn = new Arn("aws", "sns", "us-west-1", "412334153608", "topicminio");

                TopicConfig topicConfiguration = new TopicConfig(topicArn);
                List<EventType> events = new List<EventType>() { EventType.ObjectCreatedPut, EventType.ObjectCreatedCopy };
                topicConfiguration.AddEvents(events);
                topicConfiguration.AddFilterPrefix("images");
                topicConfiguration.AddFilterSuffix("jpg");
                notification.AddTopic(topicConfiguration);

                QueueConfig queueConfiguration = new QueueConfig("arn:aws:sqs:us-west-1:482314153608:testminioqueue1");
                queueConfiguration.AddEvents(new List<EventType>() { EventType.ObjectCreatedCompleteMultipartUpload });
                notification.AddQueue(queueConfiguration);

                await minio.SetBucketNotificationsAsync(new SetBucketNotificationsArgs().WithBucket(bucketName).WithBucketNotificationConfiguration(notification));
                flag = true;
            }
            else
            {
                throw new Exception($"存储桶[{bucketName}]不存在");
            }
        }
        catch (MinioException e)
        {
            throw new Exception(e.Message);
        }
        return flag;
    }

    /// <summary>
    /// 删除存储桶上所有配置的通知
    /// </summary>
    /// <param name="minio">连接实例</param>
    /// <param name="bucketName">存储桶名称</param>
    /// <returns></returns>
    private static async Task<bool> URemoveAllBucketNotifications(this IMinioClient minio, string bucketName)
    {
        bool flag = false;
        try
        {
            bool found = await minio.BucketExistsAsync(new BucketExistsArgs().WithBucket(bucketName));
            if (found)
            {
                await minio.RemoveAllBucketNotificationsAsync(new RemoveAllBucketNotificationsArgs().WithBucket(bucketName));
                flag = true;
            }
            else
            {
                throw new Exception($"存储桶[{bucketName}]不存在");
            }
        }
        catch (MinioException e)
        {
            throw new Exception(e.Message);
        }
        return flag;
    }

    #endregion

    #region 操作文件对象

    /// <summary>
    /// 从桶下载文件到本地
    /// </summary>
    /// <param name="minio">连接实例</param>
    /// <param name="bucketName">存储桶名称</param>
    /// <param name="objectName">存储桶里的对象名称</param>
    /// <param name="fileName">本地路径</param>
    /// <param name="sse"></param>
    /// <returns></returns>
    public static async Task<bool> UFGetObject(this IMinioClient minio, string bucketName, string objectName, string fileName, IServerSideEncryption? sse = null)
    {
        bool flag = false;
        try
        {
            bool found = await minio.BucketExistsAsync(new BucketExistsArgs().WithBucket(bucketName));
            if (found)
            {
                if (File.Exists(fileName))
                {
                    File.Delete(fileName);
                }
                await minio.GetObjectAsync(new GetObjectArgs().WithBucket(bucketName).WithObject(objectName).WithFile(fileName).WithServerSideEncryption(sse)).ConfigureAwait(
                    false);
                flag = true;
            }
            else
            {
                throw new Exception($"存储桶[{bucketName}]不存在");
            }
        }
        catch (MinioException e)
        {
            throw new Exception(e.Message);
        }
        return flag;
    }

    /// <summary>上传本地文件至存储桶
    /// 上传本地文件至存储桶
    /// </summary>
    /// <param name="minio">连接实例</param>
    /// <param name="bucketName">存储桶名称</param>
    /// <param name="objectName">存储桶里的对象名称</param>
    /// <param name="fileName">本地路径</param>
    /// <returns></returns>
    public static async Task<bool> UFPutObject(this IMinioClient minio, string bucketName, string objectName, string fileName)
    {
        bool flag = false;
        try
        {
            bool found = await minio.BucketExistsAsync(new BucketExistsArgs().WithBucket(bucketName));
            if (found)
            {
                await minio.UPutObjectAsync(bucketName, objectName, fileName);
                flag = true;
            }
            else
            {
                throw new Exception($"存储桶[{bucketName}]不存在");
            }
        }
        catch (MinioException e)
        {
            throw new Exception(e.Message);
        }
        return flag;
    }

    #endregion

    #region Presigned操作

    /// <summary>
    /// 生成一个给HTTP GET请求用的presigned URL。浏览器/移动端的客户端可以用这个URL进行下载，即使其所在的存储桶是私有的。这个presigned URL可以设置一个失效时间，默认值是7天。
    /// </summary>
    /// <param name="minio">连接实例</param>
    /// <param name="bucketName">存储桶名称</param>
    /// <param name="objectName">存储桶里的对象名称</param>
    /// <param name="expiresInt">失效时间（以秒为单位），默认是7天，不得大于七天</param>
    /// <param name="reqParams">额外的响应头信息，支持response-expires、response-content-type、response-cache-control、response-content-disposition</param>
    /// <returns></returns>
    public static async Task<Tuple<bool, string>> UPresignedGetObject(this IMinioClient minio, string bucketName, string objectName, int expiresInt = 1000)
    {
        bool flag = false;
        string Ret = string.Empty;
        try
        {
            bool found = await minio.BucketExistsAsync(new BucketExistsArgs().WithBucket(bucketName));
            if (found)
            {
                var reqParams = new Dictionary<string, string> { { "response-content-type", "application/json" } };
                Ret =
                    await minio.PresignedGetObjectAsync(new PresignedGetObjectArgs().WithBucket(bucketName).WithObject(objectName).WithExpiry(expiresInt).WithHeaders(reqParams));
                flag = true;
            }
            else
            {
                throw new Exception($"存储桶[{bucketName}]不存在");
            }
        }
        catch (Exception e)
        {
            throw new Exception(e.Message);
        }
        return Tuple.Create(flag, Ret);
    }

    /// <summary>
    /// 生成一个给HTTP PUT请求用的presigned URL。浏览器/移动端的客户端可以用这个URL进行上传，即使其所在的存储桶是私有的。这个presigned URL可以设置一个失效时间，默认值是7天。
    /// </summary>
    /// <param name="minio">连接实例</param>
    /// <param name="bucketName">存储桶名称</param>
    /// <param name="objectName">存储桶里的对象名称</param>
    /// <param name="expiresInt">失效时间（以秒为单位），默认是7天，不得大于七天</param>
    /// <returns></returns>
    public static async Task<Tuple<bool, string>> UPresignedPutObject(this IMinioClient minio, string bucketName, string objectName, int expiresInt = 1000)
    {
        bool flag = false;
        string Ret = string.Empty;
        try
        {
            bool found = await minio.BucketExistsAsync(new BucketExistsArgs().WithBucket(bucketName));
            if (found)
            {
                Ret = await minio.PresignedPutObjectAsync(new PresignedPutObjectArgs().WithBucket(bucketName).WithObject(objectName).WithExpiry(expiresInt));
                flag = true;
            }
            else
            {
                throw new Exception($"存储桶[{bucketName}]不存在");
            }
        }
        catch (Exception e)
        {
            throw new Exception(e.Message);
        }
        return Tuple.Create(flag, Ret);
    }

    /// <summary>
    /// 允许给POST请求的presigned URL设置策略，比如接收对象上传的存储桶名称的策略，key名称前缀，过期策略。
    /// </summary>
    /// <param name="minio">连接实例</param>
    /// <param name="PostPolicy">对象的post策略</param>
    /// <returns></returns>
    public static async Task<Tuple<bool, Uri, IDictionary<string, string>>> UPresignedPostPolicy(this IMinioClient minio)
    {
        bool flag = false;
        (Uri, IDictionary<string, string>) tdic;
        try
        {
            PostPolicy form = new PostPolicy();
            DateTime expiration = DateTime.UtcNow;
            form.SetExpires(expiration.AddDays(10));
            form.SetKey("my-objectname");
            form.SetBucket("my-bucketname");

            tdic = await minio.PresignedPostPolicyAsync(new PresignedPostPolicyArgs().WithPolicy(form));
            flag = true;
        }
        catch (Exception e)
        {
            throw new Exception(e.Message);
        }
        return Tuple.Create(flag, tdic.Item1, tdic.Item2);
    }

    #endregion

    #region 操作对象

    /// <summary>
    /// 返回对象数据流
    /// </summary>
    /// <param name="minio">连接实例</param>
    /// <param name="bucketName">存储桶名称</param>
    /// <param name="objectName">存储桶里的对象名称</param>
    /// <param name="callback">处理流的回调函数</param>
    /// <returns></returns>
    public static async Task<bool> UGetObjectAsync(this IMinioClient minio, string bucketName, string objectName, Action<Stream> callback)
    {
        bool flag = false;
        try
        {
            bool found = await minio.BucketExistsAsync(new BucketExistsArgs().WithBucket(bucketName));
            if (found)
            {
                await minio.StatObjectAsync(new StatObjectArgs().WithBucket(bucketName).WithObject(objectName));
                await minio.GetObjectAsync(new GetObjectArgs().WithBucket(bucketName).WithObject(objectName).WithCallbackStream(callback));
                flag = true;
            }
            else
            {
                throw new Exception($"存储桶[{bucketName}]不存在");
            }
        }
        catch (MinioException e)
        {
            throw new Exception(e.Message);
        }
        return flag;
    }

    /// <summary>
    /// 下载对象指定区域的字节数组做为流。offset和length都必须传
    /// </summary>
    /// <param name="minio">连接实例</param>
    /// <param name="bucketName">存储桶名称</param>
    /// <param name="objectName">存储桶里的对象名称</param>
    /// <param name="offset">offset 是起始字节的位置</param>
    /// <param name="length">length是要读取的长度</param>
    /// <param name="callback">处理流的回调函数</param>
    /// <returns></returns>
    public static async Task<bool> UGetObjectAsync(this IMinioClient minio, string bucketName, string objectName, long offset, long length, Action<Stream> callback)
    {
        bool flag = false;
        try
        {
            bool found = await minio.BucketExistsAsync(new BucketExistsArgs().WithBucket(bucketName));
            if (found)
            {
                await minio.StatObjectAsync(new StatObjectArgs().WithBucket(bucketName).WithObject(objectName));
                await minio.GetObjectAsync(new GetObjectArgs().WithBucket(bucketName).WithObject(objectName).WithOffsetAndLength(offset, length).WithCallbackStream(callback));
                flag = true;
            }
            else
            {
                throw new Exception($"存储桶[{bucketName}]不存在");
            }
        }
        catch (MinioException e)
        {
            throw new Exception(e.Message);
        }
        return flag;
    }

    /// <summary>
    /// 下载并将文件保存到本地文件系统
    /// </summary>
    /// <param name="minio">连接实例</param>
    /// <param name="bucketName">存储桶名称</param>
    /// <param name="objectName">存储桶里的对象名称</param>
    /// <param name="fileName">本地文件路径</param>
    /// <returns></returns>
    public static async Task<bool> UGetObjectAsync(this IMinioClient minio, string bucketName, string objectName, string fileName)
    {
        bool flag = false;
        try
        {
            bool found = await minio.BucketExistsAsync(new BucketExistsArgs().WithBucket(bucketName));
            if (found)
            {
                if (File.Exists(fileName))
                {
                    File.Delete(fileName);
                }
                await minio.StatObjectAsync(new StatObjectArgs().WithBucket(bucketName).WithObject(objectName));
                await minio.GetObjectAsync(new GetObjectArgs().WithBucket(bucketName).WithObject(objectName).WithFile(fileName));
                flag = true;
            }
            else
            {
                throw new Exception($"存储桶[{bucketName}]不存在");
            }
        }
        catch (MinioException e)
        {
            throw new Exception(e.Message);
        }
        return flag;
    }

    /// <summary>
    /// 通过文件上传到对象中
    /// </summary>
    /// <param name="minio">连接实例</param>
    /// <param name="bucketName">存储桶名称</param>
    /// <param name="objectName">存储桶里的对象名称</param>
    /// <param name="filePath">要上传的本地文件名</param>
    /// <param name="contentType">文件的Content type，默认是"application/octet-stream"</param>
    /// <returns></returns>
    public static async Task<bool> UPutObjectAsync(
        this IMinioClient minio,
        string bucketName,
        string objectName,
        string filePath,
        string contentType = "application/octet-stream")
    {
        bool flag = false;
        try
        {
            bool found = await minio.BucketExistsAsync(new BucketExistsArgs().WithBucket(bucketName));
            if (found)
            {
                await minio.PutObjectAsync(new PutObjectArgs().WithBucket(bucketName).WithObject(objectName).WithFileName(filePath).WithContentType(contentType));
                flag = true;
            }
            else
            {
                throw new Exception($"存储桶[{bucketName}]不存在");
            }
        }
        catch (Exception e)
        {
            throw new Exception(e.Message);
        }
        return flag;
    }

    /// <summary>
    /// 通过Stream上传对象
    /// </summary>
    /// <param name="minio">连接实例</param>
    /// <param name="bucketName">存储桶名称</param>
    /// <param name="objectName">存储桶里的对象名称</param>
    /// <param name="data">要上传的Stream对象</param>
    /// <param name="size">流的大小</param>
    /// <param name="contentType">文件的Content type，默认是"application/octet-stream"</param>
    /// <returns></returns>
    public static async Task<bool> UPutObjectAsync(
        this IMinioClient minio,
        string bucketName,
        string objectName,
        Stream data,
        long size,
        string contentType = "application/octet-stream")
    {
        bool flag = false;
        try
        {
            bool found = await minio.BucketExistsAsync(new BucketExistsArgs().WithBucket(bucketName));
            if (found)
            {
                await minio.PutObjectAsync(
                    new PutObjectArgs().WithBucket(bucketName).WithObject(objectName).WithStreamData(data).WithObjectSize(size).WithContentType(contentType));
                flag = true;
            }
            else
            {
                throw new Exception($"存储桶[{bucketName}]不存在");
            }
        }
        catch (MinioException e)
        {
            throw new Exception(e.Message);
        }
        return flag;
    }

    /// <summary>
    /// 获取对象的元数据
    /// </summary>
    /// <param name="minio">连接实例</param>
    /// <param name="bucketName">存储桶名称</param>
    /// <param name="objectName">存储桶里的对象名称</param>
    /// <returns></returns>
    public static async Task<bool> UStatObject(this IMinioClient minio, string bucketName, string bucketObject)
    {
        bool flag = false;
        try
        {
            bool found = await minio.BucketExistsAsync(new BucketExistsArgs().WithBucket(bucketName));
            if (found)
            {
                ObjectStat statObject = await minio.StatObjectAsync(new StatObjectArgs().WithBucket(bucketName).WithObject(bucketObject));
                flag = true;
            }
            else
            {
                throw new Exception($"存储桶[{bucketName}]不存在");
            }
        }
        catch (MinioException e)
        {
            throw new Exception(e.Message);
        }
        return flag;
    }

    /// <summary>
    /// 从objectName指定的对象中将数据拷贝到destObjectName指定的对象
    /// </summary>
    /// <param name="minio"></param>
    /// <param name="srcBucketName">源存储桶名称</param>
    /// <param name="srcObjectName">源存储桶中的源对象名称</param>
    /// <param name="destBucketName">目标存储桶名称</param>
    /// <param name="destObjectName">要创建的目标对象名称,如果为空，默认为源对象名称</param>
    /// <param name="copyConditions">拷贝操作的一些条件Map</param>
    /// <param name="sseSrc"></param>
    /// <param name="sseDest"></param>
    /// <returns></returns>
    public static async Task<bool> UCopyObject(
        this IMinioClient minio,
        string srcBucketName,
        string srcObjectName,
        string destBucketName,
        string destObjectName,
        CopyConditions? copyConditions = null,
        IServerSideEncryption? sseSrc = null,
        IServerSideEncryption? sseDest = null)
    {
        bool flag = false;
        try
        {
            bool found = await minio.BucketExistsAsync(new BucketExistsArgs().WithBucket(srcBucketName));
            if (!found)
            {
                throw new Exception($"源存储桶[{srcBucketName}]不存在");
            }
            bool foundtwo = await minio.BucketExistsAsync(new BucketExistsArgs().WithBucket(destBucketName));
            if (!foundtwo)
            {
                throw new Exception($"目标存储桶[{destBucketName}]不存在");
            }

            await minio.CopyObjectAsync(
                new CopyObjectArgs().WithCopyObjectSource(new CopySourceObjectArgs().WithBucket(srcBucketName).WithObject(srcObjectName).WithServerSideEncryption(sseSrc))
                                    .WithBucket(destBucketName).WithObject(destObjectName).WithServerSideEncryption(sseDest));
            flag = true;
        }
        catch (MinioException e)
        {
            throw new Exception(e.Message);
        }
        return flag;
    }

    /// <summary>
    /// 删除一个对象
    /// </summary>
    /// <param name="minio">连接实例</param>
    /// <param name="bucketName">存储桶名称</param>
    /// <param name="objectName">存储桶里的对象名称</param>
    /// <returns></returns>
    public static async Task<bool> URemoveObject(this IMinioClient minio, string bucketName, string objectName)
    {
        bool flag = false;
        try
        {
            bool found = await minio.BucketExistsAsync(new BucketExistsArgs().WithBucket(bucketName));
            if (found)
            {
                await minio.RemoveObjectAsync(new RemoveObjectArgs().WithBucket(bucketName).WithObject(objectName));
                flag = true;
            }
            else
            {
                throw new Exception($"存储桶[{bucketName}]不存在");
            }
        }
        catch (MinioException e)
        {
            throw new Exception(e.Message);
        }
        return flag;
    }

    /// <summary>
    /// 删除多个对象
    /// </summary>
    /// <param name="minio">连接实例</param>
    /// <param name="bucketName">存储桶名称</param>
    /// <param name="objectsList">含有多个对象名称的IEnumerable</param>
    /// <returns></returns>
    public static async Task<bool> URemoveObjects(this IMinioClient minio, string bucketName, List<string> objectsList)
    {
        bool flag = false;
        try
        {
            bool found = await minio.BucketExistsAsync(new BucketExistsArgs().WithBucket(bucketName));
            if (found)
            {
                if (objectsList.Any())
                {
                    IObservable<DeleteError> objectsOservable =
                        await minio.RemoveObjectsAsync(new RemoveObjectsArgs().WithBucket(bucketName).WithObjects(objectsList)).ConfigureAwait(false);
                    flag = true;
                }
            }
            else
            {
                throw new Exception($"存储桶[{bucketName}]不存在");
            }
        }
        catch (MinioException e)
        {
            throw new Exception(e.Message);
        }
        return flag;
    }

    /// <summary>
    /// 删除一个未完整上传的对象
    /// </summary>
    /// <param name="minio">连接实例</param>
    /// <param name="bucketName">存储桶名称</param>
    /// <param name="objectName">存储桶里的对象名称</param>
    /// <returns></returns>
    public static async Task<bool> URemoveIncompleteUpload(this IMinioClient minio, string bucketName, string objectName)
    {
        bool flag = false;
        try
        {
            bool found = await minio.BucketExistsAsync(new BucketExistsArgs().WithBucket(bucketName));
            if (found)
            {
                await minio.RemoveIncompleteUploadAsync(new RemoveIncompleteUploadArgs().WithBucket(bucketName).WithObject(objectName));
                flag = true;
            }
            else
            {
                throw new Exception($"存储桶[{bucketName}]不存在");
            }
        }
        catch (MinioException e)
        {
            throw new Exception(e.Message);
        }
        return flag;
    }

    #endregion
}
